#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "assert.h"

#include "BList.h"

#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "SpecialTerm.h"
#include "ST_floatInterval.h"


ST_floatInterval::ST_floatInterval(Sort *sort,FeatureTerm *min,FeatureTerm *max) : SpecialTerm(sort)
{
	m_min=min;
	m_max=max;

	if (m_min!=0) {
		m_names.Add(new Symbol("min"));
		m_values.Add(m_min);
	} // if 
	if (m_max!=0) {
		m_names.Add(new Symbol("max"));
		m_values.Add(m_max);
	} // if 
} /* SpecialTerm::ST_floatInterval */ 


ST_floatInterval::~ST_floatInterval(void)
{
	m_min=0;
	m_max=0;
} /* SpecialTerm::~ST_floatInterval */ 


void ST_floatInterval::createSort(Ontology *o)
{
	Sort *s;
	s=o->new_special_sort("float-interval","float",2,"min","float","max","float");
	s->setSpecialSeed(new ST_floatInterval(s,0,0));
} /* SpecialTerm::createSort */ 
							

SpecialTerm *ST_floatInterval::newSpecialTerm(Sort *sort,List<Symbol> *names,List<FeatureTerm> *arguments)
{
	FeatureTerm *minv=0;
	FeatureTerm *maxv=0;
	FeatureTerm *v;
	Symbol *n;

	if (names!=0 && arguments!=0) {
		names->Rewind();
		arguments->Rewind();
		while(names->Iterate(n) && arguments->Iterate(v)) {
			if (n->cmp("min")) minv=new FeatureTerm(v);
			if (n->cmp("max")) maxv=new FeatureTerm(v);
		} // while 
	} // if 

	return new ST_floatInterval(sort,minv,maxv);
} /* ST_floatInterval::newSpecialTerm */ 


SpecialTerm *ST_floatInterval::clone(void)
{
	SpecialTerm *st;
	List<FeatureTerm> *l;

	l=FeatureTerm::clone(&m_values);
	st=newSpecialTerm(m_sort,&m_names,l);
	delete l;

	return st;
} /* SpecialTerm::clone */ 


SpecialTerm *ST_floatInterval::clone(class FTKBase *dm)
{
	SpecialTerm *st;
	List<FeatureTerm> *l;

	l=FeatureTerm::clone(&m_values,dm);
	st=newSpecialTerm(m_sort,&m_names,l);
	delete l;

	return st;
} /* SpecialTerm::clone */ 


List<FeatureTerm> *ST_floatInterval::DSpecialization(List<FeatureTerm> *objects,Ontology *ontology,FTKBase *domain_model)
{
	List<FeatureTerm> *refinements,l;
	float objects_min,objects_max,v;
	bool no_min=false,no_max=false;
	FeatureTerm *f,*f2;
	bool first=true;

	if (objects==0 || objects->Length()==0) return 0;

	l.Instance(*objects);
	l.Rewind();
	while(l.Iterate(f)) {
		if (f->isFloat()) {
			v=f->getFloat();
			if (first) {
				objects_min=objects_max=v;
				first=false;
			} else {
				if (v<objects_min) objects_min=v;
				if (v>objects_max) objects_max=v;
			} // if
		} else if (f->isInt()) {
			v=float(f->getInt());
			if (first) {
				objects_min=objects_max=v;
				first=false;
			} else {
				if (v<objects_min) objects_min=v;
				if (v>objects_max) objects_max=v;
			} // if
		} else {
			if (f->getSort()==m_sort) {
				f2=f->featureValueQuick("min");
				if (f2!=0 && (f2->isFloat())) {
					v=f2->getFloat();
					if (first) {
						objects_min=objects_max=v;
						first=false;
					} else {
						if (v<objects_min) objects_min=v;
						if (v>objects_max) objects_max=v;
					} // if
				} else {
					no_min=true;
				} // if 
				f2=f->featureValueQuick("max");
				if (f2!=0 && (f2->isFloat())) {
					v=f2->getFloat();
					if (first) {
						objects_min=objects_max=v;
						first=false;
					} else {
						if (v<objects_min) objects_min=v;
						if (v>objects_max) objects_max=v;
					} // if
				} else {
					no_max=true;
				} // if 
			} else {
				return 0;
			} // if 
		} // if 
	} // while 

	if (m_min!=0 && (m_min->getFloat()>objects_min || no_min)) return 0;
	if (m_max!=0 && (m_max->getFloat()<objects_max || no_max)) return 0;

	refinements=new List<FeatureTerm>;

	if (!no_min) if (m_min==0 || m_min->getFloat()<objects_min) refinements->Add(new FeatureTerm((Symbol *)0,new ST_floatInterval(m_sort,new FeatureTerm((Symbol *)0,objects_min,ontology),(m_max==0 ? 0:new FeatureTerm(m_max))),m_sort));
	if (!no_max) if (m_max==0 || m_max->getFloat()>objects_max) refinements->Add(new FeatureTerm((Symbol *)0,new ST_floatInterval(m_sort,(m_min==0 ? 0:new FeatureTerm(m_min)),new FeatureTerm((Symbol *)0,objects_max,ontology)),m_sort));

	return refinements;
} /* SpecialTerm::DSpecialization */ 


bool ST_floatInterval_sort_function(float *f1,float *f2)
{
	return (*f1)<(*f2);
} // ST_floatInterval_sort_function


List<FeatureTerm> *ST_floatInterval::DSpecialization_b(List<FeatureTerm> *objects,Ontology *ontology,FTKBase *domain_model)
{
	List<FeatureTerm> *refinements,l;
	List<float> values;
	int i;
	float v;
	FeatureTerm *f,*f2;

	if (objects==0 || objects->Length()==0) return 0;

	l.Instance(*objects);
	l.Rewind();
	while(l.Iterate(f)) {
		if (f->isFloat() || f->isInt()) {
			v=(f->isFloat() ? f->getFloat():f->getInt());
			values.Add(new float(v));
		} // if 
		if (f->getSort()==m_sort) {
			f2=f->featureValueQuick("min");
			if (f2!=0 && (f2->isFloat())) {
				v=f2->getFloat();
				values.Add(new float(v));
			} // if 
			f2=f->featureValueQuick("max");
			if (f2!=0 && (f2->isFloat())) {
				v=f2->getFloat();
				values.Add(new float(v));
			} // if 
		} // if 

	} // while 

	values.Sort(&ST_floatInterval_sort_function);

	refinements=new List<FeatureTerm>;
	for(i=0;i<values.Length()-1;i++) {
		v=((*values[i])+(*values[i+1]))/2;
		if ((*values[i])!=(*values[i+1])) {
			if ((m_min==0 || m_min->getFloat()<v) &&
				(m_max==0 || m_max->getFloat()>=v)) refinements->Add(new FeatureTerm((Symbol *)0,new ST_floatInterval(m_sort,new FeatureTerm((Symbol *)0,v,ontology),(m_max==0 ? 0:new FeatureTerm(m_max))),m_sort));
			if ((m_max==0 || m_max->getFloat()>v) &&
				(m_min==0 || m_min->getFloat()<=v)) refinements->Add(new FeatureTerm((Symbol *)0,new ST_floatInterval(m_sort,(m_min==0 ? 0:new FeatureTerm(m_min)),new FeatureTerm((Symbol *)0,v,ontology)),m_sort));		
		} // if
	} // for 


	return refinements;
} /* SpecialTerm::DSpecialization_b */ 


List<FeatureTerm> *ST_floatInterval::DGeneralization(Ontology *ontology,FTKBase *domain_model)
{
	List<FeatureTerm> *refinements=new List<FeatureTerm>;
	if (m_min==0 && m_max==0) refinements->Add(new FeatureTerm((Symbol *)0,ontology->get_sort("float"),0));
	if (m_min!=0) refinements->Add(new FeatureTerm((Symbol *)0,new ST_floatInterval(m_sort,0,(m_max==0 ? 0:new FeatureTerm(m_max))),m_sort));
	if (m_max!=0) refinements->Add(new FeatureTerm((Symbol *)0,new ST_floatInterval(m_sort,(m_min==0 ? 0:new FeatureTerm(m_min)),0),m_sort));
	return refinements;
} /* SpecialTerm::DGeneralization */ 


List<FeatureTerm> *ST_floatInterval::unification(FeatureTerm *f2,Ontology *ontology,FTKBase *domain_model)
{
	ST_floatInterval *fi;
	List<FeatureTerm> *unifications;

	if (f2==0) {
		unifications=new List<FeatureTerm>;
		unifications->Add(new FeatureTerm((Symbol *)0,clone(domain_model),m_sort));
		return unifications;
	} // if 

	if (f2->isFloat() || f2->isInt()) {
		float v=(f2->isFloat() ? f2->getFloat():f2->getInt());

		if (m_min!=0 && m_min->getFloat()>v) return 0;
		if (m_max!=0 && m_max->getFloat()<v) return 0;
		unifications=new List<FeatureTerm>;
		unifications->Add(f2->clone(domain_model));
		return unifications;
	} // if 
	
	if (f2->getSort()!=m_sort) return 0;

	fi=(ST_floatInterval *)f2->getSpecialTerm();

	if (m_min!=0 && fi->m_max!=0 && m_min->getFloat()>fi->m_max->getFloat()) return 0;
	if (m_max!=0 && fi->m_min!=0 && m_max->getFloat()<fi->m_min->getFloat()) return 0;
	
	{
		FeatureTerm *vmin=0,*vmax=0;

		if (m_min!=0 && fi->m_min!=0) vmin=new FeatureTerm((Symbol *)0,(m_min->getFloat()>fi->m_min->getFloat() ? m_min->getFloat():fi->m_min->getFloat()),ontology);
		if (m_min==0 && fi->m_min!=0) vmin=new FeatureTerm(fi->m_min);
		if (m_min!=0 && fi->m_min==0) vmin=new FeatureTerm(m_min);

		if (m_max!=0 && fi->m_max!=0) vmax=new FeatureTerm((Symbol *)0,(m_max->getFloat()<fi->m_max->getFloat() ? m_max->getFloat():fi->m_max->getFloat()),ontology);
		if (m_max==0 && fi->m_max!=0) vmax=new FeatureTerm(fi->m_max);
		if (m_max!=0 && fi->m_max==0) vmax=new FeatureTerm(m_max);

		unifications=new List<FeatureTerm>;
		unifications->Add(new FeatureTerm((Symbol *)0,new ST_floatInterval(m_sort,vmin,vmax),m_sort));
	}

	return unifications;
} /* SpecialTerm::unification */ 


bool ST_floatInterval::subsumes(FeatureTerm *f)
{
	if (f->isFloat() || f->isInt()) {
		if (!f->hasValue()) return false;
		float v=(f->isFloat() ? f->getFloat():f->getInt());
		if (m_min!=0 && v<m_min->getFloat()) return false;
		if (m_max!=0 && v>m_max->getFloat()) return false;
		return true;
	} // if 
	if (f->isSpecial() && f->getSort()==m_sort) {
		ST_floatInterval *st=(ST_floatInterval *)f->getSpecialTerm();
		if (st==0) return false;
		if (m_min!=0) {
			if (st->m_min==0) return false;
			if (m_min->getFloat()>st->m_min->getFloat()) return false;
		} // if 
		if (m_max!=0) {
			if (st->m_max==0) return false;
			if (m_max->getFloat()<st->m_max->getFloat()) return false;
		} // if 
		return true;
	} // if 
	return false;
} /* SpecialTerm::subsumes */  


SpecialTerm *ST_floatInterval::random(void)
{
	switch(rand()%3) {
	case 0:
			return new ST_floatInterval(m_sort,
										new FeatureTerm((Symbol *)0,(float(rand())/float(RAND_MAX))*float(rand()),m_sort->getOntology()),
										0);
			break;
	case 1:
			return new ST_floatInterval(m_sort,
										0,
										new FeatureTerm((Symbol *)0,(float(rand())/float(RAND_MAX))*float(rand()),m_sort->getOntology()));
			break;
	case 2:	
			{
				float a=(float(rand())/float(RAND_MAX))*float(rand());
				float b=a+(float(rand())/float(RAND_MAX))*float(rand());
				return new ST_floatInterval(m_sort,
											new FeatureTerm((Symbol *)0,a,m_sort->getOntology()),
											new FeatureTerm((Symbol *)0,b,m_sort->getOntology()));
			}
			break;
	} // switch
	return 0;
} /* SpecialTerm::random */ 
